// callback: cmd_buffer

// buffer management
void cmd_buffer(istringstream& ss) {
  
  string op;
  string name;
  if(!(ss>>op)) throw "option: create|delete|copy";
  
  if(op=="create") {
    string snx, sny, snz;
    int nx,ny,nz;
    if(ss>>name>>snx) {
      if(search_buffer(name)>=0) throw "buffer name exist";
      
      if(ss>>sny>>snz) {
        nx=as_double(snx);
        ny=as_double(sny);
        nz=as_double(snz);
      } else {
        istringstream nxny(translate_var(snx));
        if(!(nxny>>nx>>ny>>nz)) throw "wrong buffer dimension";
        if(nx*ny*nz<=0) throw "wrong size";
      }
      
      buffer.push_back(new Buffer(name,nx,ny,nz));
    } else throw "parameter: name nx ny";
  }
  
  else if(op=="delete") {
    if(ss>>name) {
      int bid=search_buffer(name);
      delete buffer[bid];
      buffer.erase(buffer.begin()+bid);
    } else throw "required: name of buffer";
  }
  
  else if(op=="copy") { // copy source target
    string source, target;
    if(ss>>source>>target) {
      Buffer A; get_buffer(A,source);
      Buffer B; get_buffer(B,target);
      if(A.empty || B.empty) throw "buffer not found";
      B.copy(A);
    }
  }
  
  else if(op=="add") { // in place
    string a, b;
    if(ss>>a>>b) {
      Buffer A; get_buffer(A,a);
      Buffer B; get_buffer(B,b);
      if(A.empty) throw "buffer not found";
      if(B.empty) {
        double v=as_double(translate_var(b));
        A.add(v);
      } else A.add(B);
    } else throw "add A B";
  }
  
  else if(op=="sub") { // in place
    string a, b;
    if(ss>>a>>b) {
      Buffer A; get_buffer(A,a);
      Buffer B; get_buffer(B,b);
      if(A.empty) throw "buffer not found";
      if(B.empty) {
        double v=as_double(translate_var(b));
        A.sub(v);
      } else A.sub(B); 
    } else throw "sub A B";
  }
  
  else if(op=="mul") { // in place
    string a, b;
    if(ss>>a>>b) {
      Buffer A; get_buffer(A,a);
      Buffer B; get_buffer(B,b);
      if(A.empty) throw "buffer not found";
      if(B.empty) {
        double v=as_double(translate_var(b));
        A.mul(v);
      } else A.mul(B); 
    } else throw "mul A B";
  }
  
  else if(op=="div") { // in place
    string a, b;
    if(ss>>a>>b) {
      Buffer A; get_buffer(A,a);
      Buffer B; get_buffer(B,b);
      if(A.empty) throw "buffer not found";
      if(B.empty) {
        double v=as_double(translate_var(b));
        A.div(v);
      } else A.div(B);
    } else throw "div A B";
  }
  
  else if(op=="assign") {
    string a, sval;
    
    if(ss>>a>>sval) {
      double v=as_double(translate_var(sval));
      int bra=a.find('[');
      if(bra==a.npos) {
        Buffer A; get_buffer(A,a);
        A.fill(v);
      } else {
        string bufname;
        bufname=a.substr(0,bra);
        Buffer A; get_buffer(A,bufname);
        a.erase(0,bra+1);
        istringstream sa(replace_char(a,"[],",' '));
        int i0,i1,j0,j1,k0,k1;
        if(sa>>i0>>j0>>k0) {
          if(sa>>i1>>j1>>k1) {
            for(int i=i0;i<=i1;i++) 
              for(int j=j0;j<=j1;j++)
                for(int k=0;k<k1;k++)
                  A.value(i,j,k)=v;
          } else {
            A.value(i0,j0,k0)=v;
          }
        }
      }
    } else throw "argument:\n bufname[i0,j0,k0]\n bufname[i0,j0,k0,i1,j1,k1] value";
  }
  
  else if(op=="fill") {
    string a,sval;
    if(ss>>a>>sval) {
      Buffer A; get_buffer(A,a);
      if(sval=="x"||sval=="y"||sval=="z") {
        string delta;
        if(ss>>delta) {
          A.fill(sval,as_double(translate_var(delta)));
        } else A.fill(sval);
      } else {
        int tid=search_table(sval);
        if(tid>=0) {
          string deri;
          ss>>deri;
          if(deri=="derive") A.fill(*(table[tid]),true);
          else A.fill(*(table[tid]),false);
        }
        else A.fill(as_double(translate_var(sval)));
      }
    } else throw "argument:\n buffer table [derive]\n buffer x [delta]";
  }
  
  else if(op=="load") {
    string a,fname;
    if(ss>>a>>fname) {
      Buffer A; get_buffer(A,a);
      if(A.empty) throw "buffer not found";
      ifstream bdat(fname.c_str());
      if(bdat.fail()) throw "failed opening file";
      int n=0;
      while(bdat.good()) {
        double d;
        if(n>=A.size()) break;
        if(bdat>>d) A.ptr[n++]=d;
      }
      bdat.close();
    } else throw "syntax: load buffer file";
  }
  
  else throw "invalid operation";
  
}
